package com.kaifamiao.io.d0923;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

public class DBUtil {

    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    static {

        InputStream resourceAsStream = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        try {
            properties.load(resourceAsStream);

            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("driver");
            loadDriver();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void loadDriver(){
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }



    private Connection conn;

    public DBUtil(){

    }

    public DBUtil(String url, String user, String password){
        this.url = url;
        this.user = user;
        this.password = password;
    }

    public Connection getConnection(){
        if (conn == null){
            conn = getConnection(this.url, this.user, this.password);
        }
        return conn;
    }

    public static Connection getConnection(String url, String user, String password){
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static PreparedStatement before(Connection connection, String sql, Object...params){
        try{
            PreparedStatement statement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                statement.setObject(i + 1, params[i]);
            }
            return statement;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static int update(Connection connection, String sql, Object...params){
        PreparedStatement statement = before(connection, sql, params);
        try {
            return statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return -1;
    }

    public int update(String sql, Object...params){
        return update(getConnection(), sql, params);
    }

    public static ResultSet query(Connection connection, String sql, Object...params){
        PreparedStatement statement = before(connection, sql, params);
        try {
            return statement.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public ResultSet query(String sql, Object...params){
        return query(this.getConnection(), sql, params);
    }


    public <T> T queryOne(String sql, Class<T> tClass, Object...params){
        ResultSet set = query(this.getConnection(), sql, params);
        try {
            if (set.next()){
                return mapper(tClass, set);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 将结果集映射为 指定对象
     * @param tClass  对象的类型
     * @param resultSet 结果集数据
     * @param <T>
     * @return
     */
    private <T> T mapper(Class<T> tClass, ResultSet resultSet){
        try {
            // 获取无参构造
            Constructor<T> constructor = tClass.getDeclaredConstructor();
            // 创建对象
            T t = constructor.newInstance();
            // 获取结果集中的元信息
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 遍历结果集的每一列
            for (int i = 1; i <= metaData.getColumnCount(); i ++){
                // 获取列名
                String label = metaData.getColumnLabel(i).toLowerCase(Locale.ROOT);
                try {
                    // 通过内省机制获取属性对应信息
                    PropertyDescriptor descriptor = new PropertyDescriptor(label, tClass);
                    // 获取 setter（写） 方法
                    Method writeMethod = descriptor.getWriteMethod();
                    // 执行 setter 方法
                    writeMethod.invoke(t, resultSet.getObject(i));
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                }
            }
            return t;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

}
